/**
 * @file Play
 * @author liyong18@baidu.com
 */
/* eslint-disable */

import * as React from 'react';
import * as debounce from 'lodash/debounce';
import {render} from '../../renderers/renderer';
import {
  Component,
  PropTypes
} from 'react';
import * as assign from 'object-assign';
import {sendNotify, setAsideFolded} from '../../actions/asist';
import {connect} from 'react-redux';
import  * as ReactTooltip from 'react-tooltip';
import {uuid} from '../../util/helper';
import * as Sensor from '../visibility-sensor';
import {getSchemas} from '../../renderers/factory';

const scopes = {
  'none': ``,

  'body': `{
    "type": "page",
    "name": "UUID",
    "body": SCHEMA_PLACEHOLDER
  }`,

  'form': `{
    "type": "page",
    "name": "UUID",
    "body": {
      "title": "",
      "type": "form",
      "api": "/api/mock/saveForm?waitSeconds=1",
      "mode": "horizontal",
      "controls": SCHEMA_PLACEHOLDER,
      "submitText": null,
      "actions": null
    }
  }`,

  'form-item': `{
    "type": "page",
    "name": "UUID",
    "body": {
      "title": "",
      "type": "form",
      "mode": "horizontal",
      "controls": [
        SCHEMA_PLACEHOLDER
      ],
      "submitText": null,
      "actions": null
    }
  }`

};

@connect(null, {
  setAsideFolded,
  sendNotify
})
export default class Play extends Component {
  static propTypes = {
    className: PropTypes.string,
    asideWidth: PropTypes.number,
    useFrame: PropTypes.bool
  };

  startX = 0;
  startWidth = 0;
  schemas = null;

  constructor(props) {
    super(props);

    const query = props.location.query;
    let code = props.code || query.code;

    if (code) {
      // 格式化下 json 代码。
      try {
        code = JSON.stringify(JSON.parse(code), null, 2);
      } catch(e) {};
    }

    const schemaContent = code || JSON.stringify({
        '$schema': "http://amis.baidu.com/schemas/page.json",
        title: 'Play Ground',
        body: '请在右侧编辑'
      }, null, 2);

    this.state = {
      schemaContent: schemaContent,
      visible: false,
      schema: null,
      Editor: null,
      width: props.asideWidth || Math.round(window.innerWidth * 0.33)
    };

    this.schemas = getSchemas().map(item => ({
      uri: item.id,
      schema: item
    }));

    this.handleMouseDown = this.handleMouseDown.bind(this);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.handleMouseUp = this.handleMouseUp.bind(this);
    this.removeWindowEvents = this.removeWindowEvents.bind(this);
    this.handlePreview = this.lazyPreview.bind(this, true);
    this.lazyPreview = debounce(this.lazyPreview, 500, {
      leading: false,
      trailing: true
    });
    this.visibleChange = this.visibleChange.bind(this);
  }

  componentDidMount() {
    this.handlePreview();
    document.body.classList.add('h-full');
  }

  componentDidUpdate() {
    ReactTooltip.rebuild();
  }

  componentWillUnmount() {
    this.removeWindowEvents();
    document.body.classList.remove('h-full');
  }

  handleMouseDown(e) {
    this.startX = e.clientX;
    this.startWidth = this.state.width;

    // this.startPosition.y = e.clientY;

    window.addEventListener('mouseup', this.handleMouseUp);
    window.addEventListener('mousemove', this.handleMouseMove);
    return false;
  }

  handleMouseMove(e) {
    const diff = this.startX - e.clientX;
    e.preventDefault();

    this.setState({
      width: Math.min(800, Math.max(200, this.startWidth + diff))
    });
  }

  handleMouseUp() {
    this.removeWindowEvents();
  }

  removeWindowEvents() {
    window.removeEventListener('mouseup', this.handleMouseUp);
    window.removeEventListener('mousemove', this.handleMouseMove);
  }

  filterSchema(schemaContent) {

    const consts = {};
    consts.AMIS_USER_NAME = 'no-one';
    consts.AMIS_USER_EMAIL = 'no-one@baidu.com';
    consts.AMIS_NOW = Math.round(Date.now() / 1000);

    return Object.keys(consts)
      .reduce((schema, key) => schema.replace(new RegExp(`(\\\\\\\\)?${key}`, "g"), (_, escape) => escape ? key : consts[key]), schemaContent)
      .replace(/(\\".*?\\")|(")((?:get|post|put|delete|raw):)?(https?:\/\/.+?)(?:\?(.*?))?\2/g, (_, ignore, quota, method, api, search = '') => {
        if (ignore) {
          return _;
        }

        if (method === 'raw:') {
          return `${quota}${api}?${search ? `&${search}` : ''}${quota}`;
        }

        return `${quota}${method || ''}/api/proxy?_url=${encodeURIComponent(api)}${search ? `&${search}` : ''}${quota}`;
      });
  }

  lazyPreview(notify = false) {
    let schemaContent = this.filterSchema(this.state.schemaContent);
    const query = this.props.location.query;

    try {
      const scope = query.scope || this.props.scope;

      if (scope && scopes[scope]) {
        schemaContent = scopes[scope].replace('SCHEMA_PLACEHOLDER', schemaContent);
      }

      schemaContent = schemaContent.replace(/UUID/g, () => uuid());
      const schema = JSON.parse(schemaContent);

      this.setState({
        schema
      });
    } catch (e) {
      notify && this.props.sendNotify({
        message: this.formatMessage(e.message, schemaContent),
        level: 'error'
      });
    }
  }

  formatMessage(message, input) {
    if (/position\s?(\d+)$/.test(message)) {
      const lines = input.substring(0, parseInt(RegExp.$1, 10)).split(/\n|\r\n|\r/);
      message = `Json 语法错误，请检测。出错位置：${lines.length}，列：${lines[lines.length -1].length}。`;
    }

    return message;
  };

  visibleChange(isVisible) {
    this.setState({
      visible: isVisible
    });
  }

  render() {

    if (!this.state.schema) {
      return (
        <div className="text-center m-t-lg">
          <i className="fa fa-spinner fa-spin fa-3x fa-fw" />
        </div>
      );
    }
    const onLeave = this.props.onLeave;

    return (
      <div style={{height: '100%'}}>
        <Sensor partialVisibility delayedCall onChange={this.visibleChange}><div style={{position:'absolute', zIndex: -1, left: 0, top: 0, right: 0, bottom: 0}}></div></Sensor>
        {this.state.visible ? (
          <div className="hbox">
            <div className="page-body col pos-rlt">
              <div className="scroll-y h-full pos-abt w-full">
                {render('page', assign({
                  type: 'page',
                  name: 'playground'
                }, this.state.schema), this.props)}
              </div>
            </div>
          </div>
        ) : (
          <div className="hbox bg-light dk v-middle ">
            <div className="col v-middle text-center text-muted">不在可视区域</div>
          </div>
        )}
      </div>
    );
  }
}
